package com.abel.bigwater.kmgw

import com.abel.bigwater.data.BcdString
import com.abel.bigwater.dataserver.model.hgd.HgdaoTcpHeart
import io.netty.buffer.Unpooled
import org.junit.After
import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runners.MethodSorters
import org.slf4j.LoggerFactory
import java.io.IOException
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.AsynchronousChannelGroup
import java.nio.channels.AsynchronousSocketChannel
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class IwgServerTest {

    var sck: AsynchronousSocketChannel? = null

    @Before
    fun setUp() {
        lgr.info("准备测试 $IWG_SERVER_NAME @ $IWG_PORT...")
        val grp = AsynchronousChannelGroup.withThreadPool(Executors.newSingleThreadExecutor())
        sck = AsynchronousSocketChannel.open(grp)

        try {
            val ftr = sck!!.connect(InetSocketAddress("localhost", IWG_PORT))
            ftr[2, TimeUnit.SECONDS]
            if (ftr.isCancelled || !ftr.isDone) {
                lgr.error("服务器未开启，请开启后运行测试！")
            }
        } catch (ex: Exception) {
            lgr.error("服务器未开启，请开启后运行本用例: ${ex.message}", ex)
        }
    }

    @After
    fun tearDown() {
        try {
            sck?.shutdownOutput()
            sck?.shutdownInput()

            sck?.close()
        } catch (ex: IOException) {
            lgr.error("close exception: ${ex.message}")
        }
    }

    @Test
    fun testIwgServerHeart() {
        if (sck?.isOpen == false) return

        val hrt = HgdaoTcpHeart().apply { this.station = "10001" }
        val buf = Unpooled.buffer().also { hrt.packBuf(it) }

        val bb = ByteBuffer.allocate(buf.readableBytes())
        bb.put(ByteArray(buf.readableBytes()).also { buf.readBytes(it) }).flip()

        var ftr = sck!!.write(bb)
        sck!!.shutdownOutput()
        Thread.sleep(1 * 1000)

        ftr[5, TimeUnit.SECONDS]
        if (ftr.isCancelled || !ftr.isDone) {
            throw IOException("写入数据失败")
        } else {
            lgr.info("发送心跳包")
        }

        bb.clear()
        ftr = sck!!.read(bb)
        ftr[2, TimeUnit.SECONDS]
        bb.flip()
        lgr.info("Got from iwg-server: ${ByteArray(bb.remaining()).also {
            bb.get(it)
        }.toString(Charsets.ISO_8859_1)}")
    }

    @Test
    fun testIwgUdpData() {
        if (sck?.isOpen == false) return

        val ba = BcdString.toByteArray(DEMO_HEX_STRING)

        val bb = ByteBuffer.allocate(ba!!.size).also {
            it.put(ba)
            it.flip()
        }

        var ftr = sck!!.write(bb)
        ftr[2, TimeUnit.SECONDS]
        lgr.info("write udp-data to iwg-server")

        Thread.sleep(1 * 1000)
        bb.clear()
        ftr = sck!!.read(bb)
        bb.flip()
        ftr[1, TimeUnit.SECONDS]
        lgr.info("Got from iwg-server: ${ByteArray(bb.remaining()).also {
            bb.get(it)
        }.toString(Charsets.ISO_8859_1)}")
    }

    companion object {
        private val lgr = LoggerFactory.getLogger(IwgServerTest::class.java)

        const val IWG_SERVER_NAME = "IWG大表服务"
        const val IWG_PORT = 6136

        const val DEMO_HEX_STRING = """AB CD 00 7D 00 66 11 05 24 16 15 03 0F 02 CE 00 05
        1E 44 31 31 35 3B 31 2E 34 3B 31 2E 30 2E 31 31 20 20 20 20 20 00 00 00 00 00 00 00 00
        01 01 0B 01 00 00 37 07 00 00 38 07 00 00 48 07 00 00
        01 02 0B 00 00 00 01 02 00 00 03 02 00 00 05 02 00 00
        02 03 01 01 00
        03 04 01 01 00
        04 05 3E 4C CC CD 3E 80 00 00 3E 8F 5C 29
        05 0D 00 12 00 13 40 11
        06 0E 00 12 67 89 00 12 64 89 00 32 67 80
        6A 0D 0A AB CD"""
    }
}